﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports Microsoft.Samples.WindowsPhoneCloud.Web.Models
Imports System.Data.Entity.ModelConfiguration.Conventions
Imports System.Data.Entity
Imports System.Collections.Generic

Namespace Infrastructure

    ' Summary:
    '     Sample Entity Framework 4.1 context class intended for connecting with SQL Azure.
    '     Place a DbSet<T> property for each collection of entities that should be queried from the database.
#If ACS Then
    Public Class SqlDataContext
        Inherits DbContext
        Implements IUserPrivilegesRepository, IPushUserEndpointsRepository, IUserRepository
#Else
    Public Class SqlDataContext
        Inherits DbContext
        Implements IUserPrivilegesRepository, IPushUserEndpointsRepository
#End If

        Public Const PushUserTableName As String = "PushUserEndpoints"

        Private Const PublicUserId As String = "00000000-0000-0000-0000-000000000000"

        Public Sub New()
            MyBase.New(ConfigReader.GetConfigValue("SqlSampleDataContextConnectionString"))
        End Sub

        Public Property SqlSampleData() As DbSet(Of SqlSampleData)

        Public Property UserPrivileges() As DbSet(Of UserPrivilege)

        Public Property PushUserEndpoints() As DbSet(Of PushUserEndpoint)

        Public Property QueuedPushNotifications() As DbSet(Of QueuedPushNotification)

#If ACS Then
		Public Property Users() As DbSet(Of User)

        Public Sub CreateUser(ByVal userId As String, ByVal userName As String, ByVal email As String) Implements IUserRepository.CreateUser
            If Me.Users.Where(Function(u) u.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase) OrElse u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)).ToList().FirstOrDefault() IsNot Nothing Then
                Throw New System.ServiceModel.Web.WebFaultException(Of String)("A user with the same id or email already exists.", System.Net.HttpStatusCode.BadRequest)
            End If

            Me.Users.Add(New User With {.UserId = userId, .Name = userName, .Email = email})

            Me.SaveChanges()
        End Sub

        Public Function GetAllUsers() As IEnumerable(Of User) Implements IUserRepository.GetAllUsers
            Return Me.Users.ToList()
        End Function

        Public Function GetUser(ByVal userId As String) As User Implements IUserRepository.GetUser
            Return Me.Users.Where(Function(u) u.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase)).ToList().FirstOrDefault()
        End Function

        Public Function GetUserByEmail(ByVal email As String) As User
            Return Me.Users.Where(Function(u) u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)).ToList().FirstOrDefault()
        End Function

        Public Function UserExists(ByVal userId As String) As Boolean Implements IUserRepository.UserExists
            Return Me.GetUser(userId) IsNot Nothing
        End Function
#End If

        Public Function GetUsersWithPrivilege(ByVal privilege As String) As IEnumerable(Of UserPrivilege) Implements IUserPrivilegesRepository.GetUsersWithPrivilege
            Return Me.UserPrivileges.Where(Function(p) p.Privilege.Equals(privilege, StringComparison.OrdinalIgnoreCase)).ToList()
        End Function

        Public Sub AddSampleData(ByVal id As Integer, ByVal title As String, ByVal isPublic As Boolean, ByVal [date] As Date)
            Me.SqlSampleData.Add(New SqlSampleData With {.Id = id, .Title = title, .IsPublic = isPublic, .Date = [date]})

            Me.SaveChanges()
        End Sub

        Public Sub AddPrivilegeToUser(ByVal userId As String, ByVal privilege As String) Implements IUserPrivilegesRepository.AddPrivilegeToUser
            If Not Me.HasUserPrivilege(userId, privilege) Then
                Me.UserPrivileges.Add(New UserPrivilege With {.UserId = userId, .Privilege = privilege})
                Me.SaveChanges()
            End If
        End Sub

        Public Sub AddPublicPrivilege(ByVal privilege As String) Implements IUserPrivilegesRepository.AddPublicPrivilege
            Me.AddPrivilegeToUser(PublicUserId, privilege)
        End Sub

        Public Sub RemovePrivilegeFromUser(ByVal userId As String, ByVal privilege As String) Implements IUserPrivilegesRepository.RemovePrivilegeFromUser
            Dim userPrivilege = Me.GetUserPrivilege(userId, privilege)
            If userPrivilege IsNot Nothing Then
                Me.UserPrivileges.Remove(userPrivilege)
                Me.SaveChanges()
            End If
        End Sub

        Public Sub DeletePublicPrivilege(ByVal privilege As String) Implements IUserPrivilegesRepository.DeletePublicPrivilege
            Me.RemovePrivilegeFromUser(PublicUserId, privilege)
        End Sub

        Public Sub DeletePrivilege(ByVal privilege As String) Implements IUserPrivilegesRepository.DeletePrivilege
            Dim userPrivileges = Me.GetUsersWithPrivilege(privilege)
            For Each userPrivilege In userPrivileges
                Me.UserPrivileges.Remove(userPrivilege)
            Next userPrivilege

            Me.SaveChanges()
        End Sub

        Public Function HasUserPrivilege(ByVal userId As String, ByVal privilege As String) As Boolean Implements IUserPrivilegesRepository.HasUserPrivilege
            Return Me.GetUserPrivilege(userId, privilege) IsNot Nothing
        End Function

        Public Function PublicPrivilegeExists(ByVal privilege As String) As Boolean Implements IUserPrivilegesRepository.PublicPrivilegeExists
            Return Me.HasUserPrivilege(PublicUserId, privilege)
        End Function

        Public Sub AddPushUserEndpoint(ByVal pushUserEndpoint As PushUserEndpoint) Implements IPushUserEndpointsRepository.AddPushUserEndpoint
            Me.PushUserEndpoints.Add(pushUserEndpoint)
            Me.SaveChanges()
        End Sub

        Public Sub UpdatePushUserEndpoint(ByVal pushUserEndpoint As PushUserEndpoint) Implements IPushUserEndpointsRepository.UpdatePushUserEndpoint
            Dim storedPushUser = Me.GetPushUserEndpointByChannel(New Uri(pushUserEndpoint.ChannelUri))
            If storedPushUser Is Nothing Then
                Throw New ArgumentException("Push user endpoint not in repository", "pushUserEndpoint")
            End If

            storedPushUser.TileCount = pushUserEndpoint.TileCount
            storedPushUser.UserId = pushUserEndpoint.UserId
            Me.SaveChanges()
        End Sub

        Public Sub RemovePushUserEndpoint(ByVal pushUserEndpoint As PushUserEndpoint) Implements IPushUserEndpointsRepository.RemovePushUserEndpoint
            Dim storedPushUser = Me.GetPushUserByApplicationAndDevice(pushUserEndpoint.ApplicationId, pushUserEndpoint.DeviceId)
            If storedPushUser.QueuedPushNotifications IsNot Nothing Then
                For Each message In storedPushUser.QueuedPushNotifications
                    Me.QueuedPushNotifications.Remove(message)
                Next message
            End If

            Me.PushUserEndpoints.Remove(storedPushUser)
            Me.SaveChanges()
        End Sub

        Public Function GetAllPushUsers() As IEnumerable(Of String) Implements IPushUserEndpointsRepository.GetAllPushUsers
            Return Me.PushUserEndpoints.ToList().GroupBy(Function(u) u.UserId).Select(Function(g) g.Key)
        End Function

        Public Function GetPushUserEndpointByChannel(ByVal channelUri As Uri) As PushUserEndpoint Implements IPushUserEndpointsRepository.GetPushUserEndpointByChannel
            Dim channel = channelUri.ToString()
            Return Me.PushUserEndpoints.SingleOrDefault(Function(u) u.ChannelUri.Equals(channel, StringComparison.OrdinalIgnoreCase))
        End Function

        <CLSCompliant(False)> _
        Public Function GetPushUserByApplicationAndDevice(ByVal applicationId As String, ByVal deviceId As String) As PushUserEndpoint Implements IPushUserEndpointsRepository.GetPushUserByApplicationAndDevice
            Return Me.PushUserEndpoints.SingleOrDefault(Function(u) u.ApplicationId.Equals(applicationId, StringComparison.OrdinalIgnoreCase) AndAlso u.DeviceId.Equals(deviceId, StringComparison.OrdinalIgnoreCase))
        End Function

        Public Function GetPushUsersByName(ByVal userId As String) As IEnumerable(Of PushUserEndpoint) Implements IPushUserEndpointsRepository.GetPushUsersByName
            Return Me.PushUserEndpoints.Where(Function(u) u.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase)).ToList()
        End Function

        Public Function GetQueuedPushNotificationsByChannel(ByVal channelUri As Uri) As IEnumerable(Of QueuedPushNotification) Implements IPushUserEndpointsRepository.GetQueuedPushNotificationsByChannel
            Dim channel = channelUri.ToString()
            Return Me.QueuedPushNotifications.Where(Function(p) p.ChannelUri.Equals(channel, StringComparison.OrdinalIgnoreCase))
        End Function

        Public Sub DeleteQueuedMessage(ByVal message As QueuedPushNotification) Implements IPushUserEndpointsRepository.DeleteQueuedMessage
            Me.QueuedPushNotifications.Remove(message)
            Me.SaveChanges()
        End Sub

        Public Sub AddQueuedPushNotification(ByVal queuedPushNotification As QueuedPushNotification) Implements IPushUserEndpointsRepository.AddQueuedPushNotification
            Me.QueuedPushNotifications.Add(queuedPushNotification)
            Me.SaveChanges()
        End Sub


        Protected Overrides Sub OnModelCreating(ByVal modelBuilder As DbModelBuilder)
            modelBuilder.Conventions.Remove(Of PluralizingEntitySetNameConvention)()
            modelBuilder.Conventions.Remove(Of PluralizingTableNameConvention)()
        End Sub

        Private Function GetUserPrivilege(ByVal userId As String, ByVal privilege As String) As UserPrivilege
            Return Me.UserPrivileges.Where(Function(p) p.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase) AndAlso p.Privilege.Equals(privilege, StringComparison.OrdinalIgnoreCase)).ToList().FirstOrDefault()
        End Function
    End Class
End Namespace